#ifndef SEARCH_H__
#define SEARCH_H__

#include "../base/client-id.h"
#include "../base/file-list.h"
#include <vector>
#include <string>
#include <utility>
#include <set>
#include <map>

class ClientInfo;

class Search {
public:
    class SearchResult {
    public:
        SearchResult() {
        }

        virtual ~SearchResult() {
        }

        // cand un rezultat este gasit, 'Search::find()' apeleaza
        // aceasta functie pentru a-l trimite destinatarului
        virtual void new_result(const ClientInfo* client,
                                const FileList::File* file) const = 0;

    private:
    };

    Search();
    ~Search();

    // cauta un fisier care corespunde cautarii din text.
    // returneaza true daca nu a aparut nici o eroare
    // (eg. 'text' e format gresit)
    bool find(const std::string& text, SearchResult* result);

    // adauga un client index
    // nu este facuta nici o copie obiectului trimis
    // daca adaugarea reuseste returneaza 'false' 
    // (nici o eroare nu a aparut).
    bool add_client(const ClientInfo* client);

    // cand un anumit client se deconecteaza de la retea
    // listele trebuie aduse la zi
    void del_client(ClientId client);

private:
    // primeste un fingerprint si intoarce o copie a acestui finger
    // print pe care instanta Search o detine
    const FingerPrint* fingerprint(const FingerPrint* finger);

    // daca este necesar, mareste dimensiunea hashului
    // pentru a realiza cautarea/inserarea/stergerea
    // intr-un timp rezonabil
    void adjust_hashtable();

    // insereaza o pereche <cuvant, amprenta> in hash
    void insert_print(uint64_t word, const FingerPrint* finger);

    // sterge o pereche <cuvant, amprenta> din hash
    void delete_print(uint64_t word, const FingerPrint* finger);

    // intoarce lista de amprente ce corespund cuvantului
    const std::set<FingerPrint*>* find_print(uint64_t word) const;

    // structura ce tine mine pentru fiecare amprenta
    // numele de fisierelor care au acea amprenta
    std::map<const FingerPrint*,
             std::vector<std::pair<ClientId, std::string> >,
             CompareFingerPrintPointer> filelist_;

    // lista de amprente a tutor fisierelor
    // fiecare amprenta este unica
    std::set<const FingerPrint*, CompareFingerPrintPointer> fingers_;

    // in hash retinem perechi de forma <cuvant, multime amprente>
    // unde 'multime amprente' reprezinta o multime de aprente
    // pentru care exista un nume ce contine cuvantul respectiv
    std::vector<std::map<
        uint64_t,
        std::set<const FingerPrint*,
                 CompareFingerPrintPointer> > > hash_[2];

    uint32_t hashsize_;          // dimensiunea hashului
    uint32_t hashelements_;      // numarul de elemente introduse
                                 // in hash
};

#endif
